<?php

namespace Mogod\Core\Model;

/**
 * Модель
 *
 * @package Mogod\Core\Model;
 * @author morph, goorus
 */
abstract class Model implements \ArrayAccess
{
	/**
	 * Брокер подключаемых методов
	 *
	 * @access protected
	 * @var \Mogod\Core\MethodBroker\MethodBrokerAbstract
	 */
	protected $broker;

	/**
	 * Внутренние переменные модели
	 *
	 * @access protected
	 * @var array
	 */
	protected $data;

	/**
	 * Поля модели
	 *
	 * @access protected
	 * @var array
	 */
	protected $fields;

	/**
	 * @param string $method
	 * @param array $args
	 */
	public function __call($method, $args)
	{
		return $this->delegate($method, $args);
	}

	/**
	 * @param array $fields
	 */
	public function __construct($fields = array())
	{
		$this->fields = $fields;
	}

	/**
	 * @param string $field
	 */
	public function __get($field)
	{
		return $this->getField($field);
	}

	/**
	 * @param string $field
	 * @param mixed $value
	 * @return \Mogod\Core\Model\Model
	 */
	public function __set($field, $value)
	{
		$this->setField($field, $value);
		return $this;
	}

	/**
	 * Получает внутреннюю переменную модели (если передан ключ) или устанавливает
	 * ее (если первым аргументов передам массив или передано значение
	 * ременной)
	 *
	 * @param string $key Ключ
	 * @param mixed $value (optional) Значение
	 * @return mixed
	 */
	public function data($key, $value = null)
	{
		if (is_string($key) && func_num_args() == 2) {
			$this->data[$key] = $value;
		} elseif (is_array($key)) {
			$this->data = array_merge((array) $this->data, $key);
		} else {
			return isset($this->data[$key]) ? $this->data[$key] : null;
		}
	}

	/**
	 * Вызов метода через брокера
	 *
	 * @param string $method
	 * @param array $args
	 * @return mixed
	 */
	public function delegate($method, $args)
	{
		if (!$this->broker) {
			return null;
		}
		return $this->broker->call($this, $method, $args);
	}

	/**
	 * Получить все внутренние переменные модели
	 *
	 * @return array
	 */
	public function getData()
	{
		return $this->data;
	}

	/**
	 * Получить определенное поле модели
	 *
	 * @param string $field
	 * @return mixed
	 */
	public function getField($field)
	{
		return isset($this->fields[$field])
			? $this->fields[$field]
			: null;
	}

	/**
	 * Получить поля модели
	 *
	 * @return array
	 */
	public function getFields()
	{
		return $this->fields;
	}

	/**
	 * Возвращает текущий брокер методов
	 *
	 * @return \Mogod\Core\MethodBroker\MethodBrokerAbstract
	 */
	public function getBroker()
	{
		return $this->broker;
	}

	/**
	 * Возвращает полное имя модели (с именем namespace)
	 *
	 * @return string
	 */
	public function getName()
	{
		return get_class($this);
	}

	/**
	 * Возвращает пространство имен модели
	 *
	 * @return string
	 */
	public function getNamespace()
	{
		$className = get_class($this);
		$pos = strrpos($className, '\\');
		return substr($className, 0, (int) $pos);
	}

	/**
	 * Возвращает имя модели
	 *
	 * @return string
	 */
	public function getShortName()
	{
		$className = get_class($this);
		$pos = strrpos($className, '\\');
		return substr($className, ((int) $pos) + 1);
	}

	/**
	 * Проверяет существует ли поле у модели
	 *
	 * @param string $field
	 * @return boolean
	 */
	public function hasField($field)
	{
		return isset($this->fields[$field]);
	}

	/**
	 * @see \Mogod\Core\Model\Model::hasField
	 */
	public function offsetExists($field)
	{
		return $this->hasField($field);
	}

	/**
	 * @see \Mogod\Core\Model\Model::getField
	 */
	public function offsetGet($field)
	{
		return $this->getField($field);
	}

	/**
	 * @see \Mogod\Core\Model\Model::setField
	 * @return \Mogod\Core\Model\Model
	 */
	public function offsetSet ($field, $value)
	{
		$this->setField($field, $value);
		return $this;
	}

	/**
	 * @see Mogod\Core\Model\Model::unsetField
	 */
	public function offsetUnset ($field)
	{
		$this->unsetField($field);
	}

	/**
	 * Изменить внутренние переменные модели
	 *
	 * @param array $data
	 */
	public function setData($data)
	{
		$this->data = $data;
	}

	/**
	 * Изменить значение определенного поля
	 *
	 * @param string $field
	 * @param mixed $value
	 */
	public function setField($field, $value)
	{
		$this->fields[$field] = $value;
	}

	/**
	 * Изменить поля модели
	 *
	 * @param array $fields
	 */
	public function setFields($fields)
	{
		$this->fields = $fields;
	}

	/**
	 * Устанавливает брокер методов
	 *
	 * @param \Mogod\Core\MethodBroker\MethodBrokerAbstract $broker
	 * @return \Mogod\Core\Model\Model
	 */
	public function setBroker($broker)
	{
		$this->broker = $broker;
		return $this;
	}

	/**
	 * Исключение поля из модели
	 *
	 * @param string $field название поля
	 */
	public function unsetField($field)
	{
		if (isset($this->fields[$field])) {
			unset($this->fields[$field]);
		}
	}

}